package com.namo.cchfile.service.impl;


import cn.hutool.core.img.Img;
import com.namo.cchcommon.api.ResultCode;
import com.namo.cchcommon.exception.ApiException;
import com.namo.cchfile.entity.FileEntity;
import com.namo.cchfile.service.FileService;
import io.minio.*;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @author WangXin
 * @date 2021/3/31 10:59
 */
@Service
@Slf4j
public class FileServiceImpl implements FileService {
    @Autowired
    private MinioClient minioClient;

    @Value("${minio.endpoint}")
    private String endpoint;
    @Value("${minio.bucketName}")
    private String bucketName;

    @Value("${minio.accessKey}")
    private String accessKey;
    @Value("${minio.secretKey}")
    private String secretKey;

    @Value("${minio.server}")
    private String server;

    /**
     * 删除文件
     * @param objectName
     * @return
     */
    @Override
    public boolean delete(String objectName) {
        //直接删除用户输入的文件名，尝试删除
        Object fileObj = null;
        try {
            //删除没有文件的时候不会报错,所以要判断文件是否存在，不存在会抛异常
            fileObj = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
            //如果找到文件执行删除
            if (fileObj != null) {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
            }
            return true;
        } catch (Exception e) {
            //没有找到捕获异常
            log.warn("用户输入的文件名："+objectName+"    未找到");
        }
        //再次尝试寻找删除，采用字符串匹配
        try {
            //是否找到的标志
            boolean isFind = false;
            //递归列出文件对象
            Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).recursive(true).build());
            //判断对象列表中文件是否存在（indexOf）
            for (Result<Item> result : results) {
                if (result.get().objectName().indexOf(objectName) != -1) {
                    objectName = result.get().objectName();
                    isFind = true;
                    break;
                }
            }
            //未找到抛异常出去
            if (isFind == false) {
                log.error("未找到要删除的文件");
                throw new ApiException(500L, "删除文件失败，未找到要删除的文件");
            }
            //调用删除文件
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
            log.info("对象："+objectName+"  删除成功");
            return true;
        }catch (ApiException e){
            //传递上面的API异常
            throw new ApiException(500L, e.getMessage());
        }catch (Exception e) {
            log.error("递归寻找，删除失败--------" + e.getMessage());
            throw new ApiException(500L, "删除文件失败");
        }
    }

    /**
     * 上传文件
     *
     * @param file
     * @param quality
     * @param expiry
     * @return
     */
    @Override
    public FileEntity uploadFile(MultipartFile file, Double quality, Integer expiry) {
        log.info("上传的文件类型为：{}  ----上传参数为：{}" + file.getContentType() + ("质量：" + quality + "过期：" + expiry));
        //构造日期文件夹路径
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        // 设置存储对象名称,随机字符串
        String objectName = null;
        try {
            objectName = UUID.randomUUID() + "." + this.getLastFileName(file.getOriginalFilename());
        } catch (Exception e) {
            log.error("后缀名获取错误---------" + e.getMessage());
            throw new ApiException(500L, "文件名错误");
        }
        //拼接最后的路径和文件名
        objectName = sdf.format(new Date()) + "/" + objectName;
        //获取文件输入流
        InputStream fileInputStream = null;
        try {
            fileInputStream = file.getInputStream();
        } catch (IOException e) {
            log.error("输入流获取错误---------" + e.getMessage());
            throw new ApiException(500L, "上传文件错误");
        }
        //判断参数expiry合理性
        if (quality <= 0 || quality > 1.0) {
            log.error("expiry参数范围错误--------");
            throw new ApiException(500L, "expiry参数范围错误");
        }
        //文件大小
        Long objectSize = 0L;
        //设置图片质量
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try {
            //设置图片压缩（仅支持jpg）
            Img.from(fileInputStream)
                    //压缩比率
                    .setQuality(quality)
                    //写入输出流
                    .write(byteArrayOutputStream);
            fileInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            //设置文件大小
            objectSize = Long.valueOf(fileInputStream.available());
        } catch (IOException e) {
            log.error("获取文件大小错误---------" + e.getMessage());
            throw new ApiException(500L, "上传文件错误");
        } catch (Exception e) {
            log.error("图片压缩错误---------" + e.getMessage());
            throw new ApiException(500L, "图片压缩错误");
        }
        //构造上传参数
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .contentType(file.getContentType())
                .stream(fileInputStream, objectSize, ObjectWriteArgs.MIN_MULTIPART_SIZE).build();
        // 使用putObject上传一个文件到存储桶中
        try {
            minioClient.putObject(putObjectArgs);
        } catch (Exception e) {
            log.error("文件上传存储对象错误--------" + e.getMessage());
            throw new ApiException(500L, "上传文件错误");
        }
        //设置返回
        FileEntity fileEntity = new FileEntity();
        //设置返回-----文件名（用于删除）
        fileEntity.setName(objectName);
        //设置返回-----访问路径
        fileEntity.setUrl(server + "/" + bucketName + "/" + objectName);
        //设置过期时间
        fileEntity.setExpiry(expiry);
        //设置图片质量
        fileEntity.setQuality(quality);
        //设置创建时间
        fileEntity.setCreateTime(new Date());
        log.info("文件上传成功");
        //TODO 设置过期时间
        return fileEntity;
    }

    /**
     * 获取文件后缀名，如果没有后缀名直接返回原文件名
     *
     * @param fileName 输入文件名
     * @return 输出后缀名（文件名）
     * @throws Exception
     */
    private String getLastFileName(String fileName) throws Exception {
        //判断输入有问题则抛异常
        if (fileName == null || fileName == "") {
            throw new ApiException(ResultCode.FAILED, "输入文件名为空");
        }
        //分割字符串
        String[] splitFileName = fileName.split("\\.");
        //判断是否有后缀名
        if (splitFileName.length <= 0) {
            return fileName;
        } else {
            return splitFileName[splitFileName.length - 1];
        }
    }

    /**
     *
     * @param start
     * @param stop
     * @return
     */
    private List<FileEntity> getFiles(Date start,Date stop){

        return null;
    }
}
